package com.lightjet.macross.base.auth.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

import javax.annotation.Resource;
import java.security.KeyPair;
import java.util.*;

/**
 * @author : lijia
 * @version : 1.0 2019-10-22 14:24
 * description : 认证服务配置
 */

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfigure extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    RedisConnectionFactory redisConnectionFactory;

    @Resource(name = "clientDetailsServiceImpl")
    ClientDetailsService clientDetailsService;


    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        //默认是不支持表单提交，这里修改提交权限
        oauthServer.allowFormAuthenticationForClients().passwordEncoder(new NoopPasswordEncoder());

        /*security
                .tokenKeyAccess("permitAll()")  //  /oauth/token_key 开发访问路径
                .checkTokenAccess("permitAll()")  //  /oauth/check_token
                .allowFormAuthenticationForClients();
        super.configure(security);*/
    }

    //配置第三方客户App 信息（即需要调用的外部系统相关信息）
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //测试情况 只在内存中存放 client 也就是第三方应用 或者说 需要调用微服务的 系统 相关信息
        /*clients.inMemory().withClient("qcs802")//.resourceIds("ht802")
                .authorizedGrantTypes("password","client_credentials", "refresh_token")  //采用 ss 密码模式
                .scopes("all").authorities("ADMIN") //权限范围及角色
                .secret("{noop}802sastcasc!") //客户应用密码密码
                .accessTokenValiditySeconds(60 * 60 * 24) //token 有效时间
                .refreshTokenValiditySeconds(60 * 60 * 24* 30); //token 刷新时间*/
        clients.withClientDetails(clientDetailsService);
        super.configure(clients);
    }



    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.accessTokenConverter(accessTokenConverter());
        endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager).reuseRefreshTokens(false);
        //endpoints.setClientDetailsService(clientDetailsService());

/*        endpoints.setClientDetailsService(clientDetailsService());
        endpoints.authenticationManager(authenticationManager)
                .accessTokenConverter(jwtAccessTokenConverter());//这里配置JWT加密，如果不想要JWT，将此行及jwtAccessTokenConverter()方法删除即可*/
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter() {
            /***
             * 重写增强token方法,用于自定义一些token总需要封装的信息
             */
            @Override
            public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
/*                String userName = authentication.getUserAuthentication().getName();
                // 得到用户名，去处理数据库可以拿到当前用户的信息和角色信息（需要传递到服务中用到的信息）
                final Map<String, Object> additionalInformation = new HashMap<>();
                // Map假装用户实体
                Map<String, String> userinfo = new HashMap<>();
                userinfo.put("id", "2230");
                userinfo.put("username", "0729");
                userinfo.put("displayname", "李佳");
                userinfo.put("pwd", "111111");
                try {
                    additionalInformation.put("userinfo", new ObjectMapper().writeValueAsString((userinfo)));
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
                ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);*/
                OAuth2AccessToken enhancedToken = super.enhance(accessToken, authentication);
                return enhancedToken;
            }
        };
        // 测试用,资源服务使用相同的字符达到一个对称加密的效果,生产时候使用RSA非对称加密方式
        accessTokenConverter.setSigningKey("SigningKey");
        return accessTokenConverter;
    }

    @Bean
    public TokenStore tokenStore() {
        RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
        return tokenStore;
    }



   /* @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        KeyPair keyPair = new KeyStoreKeyFactory(
                new ClassPathResource("keystore.jks"), "foobar".toCharArray())//jks可用jdk 工具生成
                .getKeyPair("test");
        converter.setKeyPair(keyPair);
        return converter;
    }*/


    //正常情况，这个ClientDetailsService是在业务层，继承ClientDetailsService接口，并实现loadClientByClientId(String s)方法
    public ClientDetailsService clientDetailsService(){
        return new ClientDetailsService() {
            @Override
            public ClientDetails loadClientByClientId(String s) throws ClientRegistrationException {
                return new ClientDetails() {
                    @Override
                    public String getClientId() {
                        return "qcs802";
                    }

                    @Override
                    public Set<String> getResourceIds() {
                        return null;
                    }

                    @Override
                    public boolean isSecretRequired() {
                        return true;
                    }

                    @Override
                    public String getClientSecret() {
                        return "{noop}802sastcasc!";
                    }

                    @Override
                    public boolean isScoped() {
                        return true;
                    }

                    @Override
                    public Set<String> getScope() {
                        HashSet<String> strings = new HashSet<>();
                        strings.add("all");
                        return strings;
                    }

                    @Override//这里配置支持哪几种授权模式
                    public Set<String> getAuthorizedGrantTypes() {
                        Set<String> strings = new HashSet<>();
                        strings.add("code");
                        strings.add("authorization_code");
                        strings.add("refresh_token");
                        strings.add("password");
                        return strings;
                    }

                    @Override
                    public Set<String> getRegisteredRedirectUri() {
                        Set<String> strings = new HashSet<>();
                        strings.add("http://localhost:7003/auth/account");//这里是重定向地址及最后code授权码返回地址
                        return strings;
                    }

                    @Override
                    public Collection<GrantedAuthority> getAuthorities() {
                        List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
                        grantedAuthorityList.add(new GrantedAuthority() {
                            @Override
                            public String getAuthority() {
                                return "itxsl";
                            }
                        });
                        return grantedAuthorityList;
                    }

                    @Override
                    public Integer getAccessTokenValiditySeconds() {
                        return 3600;
                    }

                    @Override
                    public Integer getRefreshTokenValiditySeconds() {
                        return 3600;
                    }

                    @Override
                    public boolean isAutoApprove(String s) {
                        return true;
                    }

                    @Override
                    public Map<String, Object> getAdditionalInformation() {
                        return null;
                    }
                };
            }
        };
    }

}
